# 房子的面积
house_size = [91, 72, 71, 92, 102, 82, 76, 81, 101, 87]
# 房子的价格
house_price = [128, 92, 95, 117, 135, 107, 91, 118, 145, 111]
# 步长
step = 0.00001
# 权重与偏置
weight = 1
base = 10

def neuron(x):
    '''
    神经元预测方法
    :param x: 输入参数，房间的大小
    :return:  输出参数，房间的价格
    '''
    return weight * x + base

def calcMSE():
    '''
    计算当前权重与偏置设置下的均方误差
    :return: 均方误差
    '''
    house_prediction = [neuron(item) for item in house_size]
    return sum([pow(house_prediction[i] - house_price[i], 2) for i in range(0,len(house_prediction))]) / (2*len(house_prediction))

def GradientCalc():
    """
    计算当前 weight 和 base设置下的梯度值
    :return: w的梯度值与b的梯度值
    """
    # cost 对 w 的偏微分，也就是 w 的梯度值
    cost_w = sum((neuron(house_size[i]) - house_price[i]) * house_size[i] for i in range(0, len(house_size))) / len(
        house_size)
    # cost 对 b 的偏微分，也就是 b 的梯度值
    cost_b = sum((neuron(house_size[i]) - house_price[i]) for i in range(0, len(house_size))) / len(house_size)
    # 返回结果
    return cost_w, cost_b

def train():
    """
    训练函数
    :return:
    """
    # 表示我们使用的是全局变量，否则赋值那里Python就会困惑到底使用什么变量
    global weight, base

    # 先得到梯度值
    cost_w, cost_b = GradientCalc()

    # 那么下次调整的值就应该是
    # 更新值 = 当前的值 - 步长 * 梯度值
    # 步长为每次梯度下降时前进的距离
    w_update = weight - step * cost_w
    b_update = base - step * cost_b

    # 更新各参数
    weight = w_update
    base = b_update

# 正式开始训练！一般的，神经网络中，将一次训练成为一次 epoch
for epoch in range(0, 100):
    train()
    print('result: cost = {} weight = {}, base = {}'.format(calcMSE(), weight, base))